use crate::camera;
use crate::global;
use core_api::checksum;
use std::collections::HashSet;
use std::ffi::OsString;
use std::path::Path;
use sysinfo::{Pid, ProcessesToUpdate, System};
use tauri::{command, AppHandle, Runtime, Window};
use tauri_plugin_shell::process::CommandEvent;
use tauri_plugin_shell::ShellExt;
type Result<T> = std::result::Result<T, String>;

pub const FFMPEG: &str = "ff7scre.exe";
pub const START_RECORDING: &str = "start_recording";

#[command]
pub async fn start_recording<R: Runtime>(
    app: AppHandle<R>,
    _window: Window<R>,
    output_file: &Path,
    watermark_text: String,
    force_open_camera: bool, // 是否强制开启摄像头
) -> Result<u32> {
    // while !global::read().get_detect_device_ready() {
    //     println!("等待设备检测完成...");
    //     // 等待设备检测完成
    //     tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
    // }
    let ff_pid = global::read().get_ffmpeg_pid();
    if ff_pid > 0 {
        return Ok(ff_pid);
    }
    // let (_audio, video) = global::read().get_message_manager().get_audio_video();
    // let is_open_camera = video.is_some();
    let camera_is_ok = camera::test_camera().is_ok();

    if force_open_camera && !camera_is_ok {
        return Err("无法开启摄像头!".to_string());
    }
    // 确保上级目录存在
    if let Some(dest_path) = output_file.parent() {
        let _ = std::fs::create_dir_all(dest_path);
    }
    // 保存到全局状态
    global::write().set_output_file(output_file.to_path_buf());
    let outfile = output_file.to_str().unwrap();
    let my_pid = std::process::id(); // 获取当前进程的PID

    let cmd: tauri_plugin_shell::process::Command = app.shell().sidecar(FFMPEG).unwrap().args(&[
        START_RECORDING,
        outfile,
        watermark_text.as_str(),
        camera_is_ok.to_string().as_str(),
        "0", // 用于测试运行多长时间 t>0 时用于测试
        my_pid.to_string().as_str(),
    ]);
    if let Ok((mut rx, child)) = cmd.spawn() {
        let (stop_tx, stop_rx) = tokio::sync::mpsc::channel(10);
        let mut g = global::write();
        g.set_ffmpeg(Some(child));
        g.set_ffmpeg_stop_rx(Some(stop_rx));

        tauri::async_runtime::spawn(async move {
            while let Some(event) = rx.recv().await {
                if let CommandEvent::Stderr(line_bytes) = event {
                    let line = String::from_utf8_lossy(&line_bytes);
                    println!("FFMPEG:{}", &line);
                } else if let CommandEvent::Terminated(payload) = event {
                    if stop_tx.send(payload.code.unwrap()).await.is_err() {
                        println!("接收端已关闭");
                    }
                    global::write().set_ffmpeg(None);
                    log::info!("===recording terminated:{:?}", payload);
                }
            }
            drop(stop_tx);
        });

        return Ok(ff_pid);
    }

    Err("无法启动录屏进程!".to_string())
}

#[command]
pub async fn stop_recording() -> Result<Option<String>> {
    log::info!("stop_recording  begin");
    let pid: u32 = global::write().stop_ffmpeg();
    let timeout = tokio::time::Duration::from_secs(5);
    let mut is_timeout = false;
    let stop_rx = global::write().get_ffmpeg_stop_rx();
    if let Some(mut rx) = stop_rx {
        match tokio::time::timeout(timeout, rx.recv()).await {
            Ok(Some(msg)) => println!("收到消息关闭消息: {}", msg),
            Ok(None) => println!("通道已关闭"),
            Err(_) => {
                is_timeout = true;
            }
        }
    } else {
        tokio::time::sleep(timeout).await;
        is_timeout = true;
    }

    if is_timeout {
        log::error!("接受关闭消息已超时!,强制杀死进程");
        if !global::write().kill_ffmpeg() {
            let success = kill_process(pid);
            log::error!("stop_recording kill recording by  pid={}", pid);
            if !success {
                let r = kill_process_by_names(vec![FFMPEG.to_string()]);
                log::error!("stop_recording kill recording by   name {:?}", r);
            }
        }
    }

    //此处已经保证进程已经关闭
    if let Some(outfile) = global::read().get_output_file() {
        // todo:这里可以调用ffmpeg 写入元信息
        let checksum = checksum::generate_checksum(outfile.to_str().unwrap());
        log::info!("stop_recording success checksum: {:?}", &checksum);
        return Ok(checksum);
    }

    Err("停止录屏发生错误!".to_string())
}

pub fn kill_process(pid: u32) -> bool {
    let mut system = System::new_all();
    system.refresh_processes(ProcessesToUpdate::Some(&[Pid::from_u32(pid)]), true); // 更新进程信息

    if let Some(process) = system.process(Pid::from_u32(pid)) {
        println!("find: {} - {:?}", pid, process.name());
        process.kill(); // 默认等价于 SIGTERM（Windows 是 TerminateProcess）
        true
    } else {
        println!("can not find PID: {}", pid);
        false
    }
}

pub fn kill_process_by_names(target_names: Vec<String>) -> Vec<(OsString, u8)> {
    let mut result: Vec<(OsString, u8)> = vec![]; // 存储返回结果
    let name_set: HashSet<OsString> = target_names
        .iter()
        .map(|s| OsString::from(s.to_ascii_lowercase())) // 转小写进行匹配
        .collect();

    let mut system = System::new(); // 不加载全部信息
    system.refresh_processes(ProcessesToUpdate::All, true);
    for (pid, process) in system.processes() {
        let name = process.name().to_ascii_lowercase(); // 获取进程名并转为小写
                                                        //println!("进程===========: {:?} ", process.name());
        if name_set.contains(&name) {
            // 尝试终止进程
            let killed = if process.kill() {
                println!("success kill  {:?} [PID: {}]", process.name(), pid);
                1 // 成功杀死进程，返回 1
            } else {
                println!("can not kill  {:?} [PID: {}]", process.name(), pid);
                0 // 无法杀死进程，返回 0
            };
            result.push((process.name().to_os_string(), killed));
        }
    }

    result
}

/// 获取当前所有进程的名称（可能包含重复）
pub fn get_all_process() -> Vec<String> {
    let mut system = System::new();
    system.refresh_processes(ProcessesToUpdate::All, true); // 仅刷新进程列表

    system
        .processes()
        .values()
        .map(|proc| proc.name().to_string_lossy().to_string())
        .collect()
}

pub fn check_process(target_names: Vec<String>) -> Vec<(String, u8)> {
    let mut system = System::new();
    system.refresh_processes(ProcessesToUpdate::All, true);

    // 收集当前正在运行的进程名（统一小写）
    let running_processes: HashSet<OsString> = system
        .processes()
        .values()
        .map(|p| p.name().to_ascii_lowercase())
        .collect();

    // 遍历目标进程名，判断是否存在
    target_names
        .iter()
        .map(|name| {
            let lower = OsString::from(name.to_ascii_lowercase());
            let exists = if running_processes.contains(&lower) {
                1
            } else {
                0
            };
            (name.clone(), exists)
        })
        .collect()
}

#[command]
pub async fn validate_checksum<R: Runtime>(
    _app: AppHandle<R>,
    output_file: &Path,
) -> Result<String> {
    checksum::validate_checksum(output_file.to_str().unwrap())
}
